"""对话管理器 - 对话历史和上下文管理"""

import asyncio
from typing import Dict, Any, List, Optional, Union
from datetime import datetime, timedelta
from loguru import logger

from ..database.manager import DatabaseManager


class ConversationManager:
    """对话管理器 - 管理用户对话历史和上下文"""
    
    def __init__(self, db_manager: DatabaseManager, config: Dict[str, Any]):
        self.db_manager = db_manager
        self.config = config
        self.conversation_config = config.get('conversation', {})
        
        # 对话配置
        self.max_conversation_length = self.conversation_config.get('max_length', 50)  # 最大对话轮数
        self.context_window_size = self.conversation_config.get('context_window', 10)  # 上下文窗口大小
        self.auto_summary_threshold = self.conversation_config.get('auto_summary_threshold', 20)  # 自动总结阈值
        self.conversation_timeout = self.conversation_config.get('timeout_hours', 24)  # 对话超时时间（小时）
        self.max_conversations_per_user = self.conversation_config.get('max_per_user', 100)
        
        # 初始化状态
        self.is_initialized = False
        self.active_conversations = {}  # 活跃对话缓存
        
        logger.info("对话管理器已创建")
    
    async def initialize(self):
        """初始化对话管理器"""
        if self.is_initialized:
            logger.warning("对话管理器已初始化")
            return
        
        try:
            # 确保数据库连接已初始化
            if not self.db_manager.is_initialized:
                await self.db_manager.initialize()
            
            # 加载活跃对话
            await self._load_active_conversations()
            
            self.is_initialized = True
            logger.info("对话管理器初始化完成")
            
        except Exception as e:
            logger.error(f"初始化对话管理器失败: {e}")
            raise
    
    async def shutdown(self):
        """关闭对话管理器"""
        if not self.is_initialized:
            logger.warning("对话管理器未初始化")
            return
        
        try:
            # 保存活跃对话
            await self._save_active_conversations()
            
            self.active_conversations.clear()
            self.is_initialized = False
            logger.info("对话管理器已关闭")
            
        except Exception as e:
            logger.error(f"关闭对话管理器失败: {e}")
    
    async def _load_active_conversations(self):
        """加载活跃对话"""
        try:
            # 从Redis加载活跃对话
            active_keys = await self.db_manager.redis_client.get_keys_pattern(
                "conversation:active:*"
            )
            
            for key in active_keys:
                conversation_data = await self.db_manager.redis_client.get_hash(key)
                if conversation_data:
                    conversation_id = key.split(':')[-1]
                    self.active_conversations[conversation_id] = conversation_data
            
            logger.debug(f"加载了 {len(self.active_conversations)} 个活跃对话")
            
        except Exception as e:
            logger.error(f"加载活跃对话失败: {e}")
    
    async def _save_active_conversations(self):
        """保存活跃对话"""
        try:
            for conversation_id, conversation_data in self.active_conversations.items():
                await self.db_manager.redis_client.set_hash(
                    f"conversation:active:{conversation_id}",
                    conversation_data,
                    expire=self.conversation_timeout * 3600
                )
            
            logger.debug(f"保存了 {len(self.active_conversations)} 个活跃对话")
            
        except Exception as e:
            logger.error(f"保存活跃对话失败: {e}")
    
    async def create_conversation(self, user_id: str, title: Optional[str] = None,
                                metadata: Optional[Dict[str, Any]] = None) -> str:
        """创建新对话"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            import uuid
            conversation_id = str(uuid.uuid4())
            timestamp = datetime.utcnow()
            
            # 准备对话数据
            conversation_data = {
                'conversation_id': conversation_id,
                'user_id': user_id,
                'title': title or f"对话 {timestamp.strftime('%Y-%m-%d %H:%M')}",
                'created_at': timestamp,
                'updated_at': timestamp,
                'message_count': 0,
                'status': 'active',
                'metadata': metadata or {},
                'messages': []
            }
            
            # 存储到MongoDB（持久化）
            await self.db_manager.mongodb_client.store_conversation(conversation_data)
            
            # 添加到活跃对话缓存
            self.active_conversations[conversation_id] = {
                'conversation_id': conversation_id,
                'user_id': user_id,
                'title': conversation_data['title'],
                'created_at': timestamp.isoformat(),
                'updated_at': timestamp.isoformat(),
                'message_count': 0,
                'status': 'active'
            }
            
            # 存储到Redis（快速访问）
            await self.db_manager.redis_client.set_hash(
                f"conversation:active:{conversation_id}",
                self.active_conversations[conversation_id],
                expire=self.conversation_timeout * 3600
            )
            
            logger.info(f"创建对话: {conversation_id} - {user_id}")
            return conversation_id
            
        except Exception as e:
            logger.error(f"创建对话失败: {e}")
            raise
    
    async def add_message(self, conversation_id: str, role: str, content: str,
                         metadata: Optional[Dict[str, Any]] = None) -> str:
        """添加消息到对话"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            import uuid
            message_id = str(uuid.uuid4())
            timestamp = datetime.utcnow()
            
            # 准备消息数据
            message_data = {
                'message_id': message_id,
                'conversation_id': conversation_id,
                'role': role,  # 'user', 'assistant', 'system'
                'content': content,
                'timestamp': timestamp,
                'metadata': metadata or {}
            }
            
            # 获取对话信息
            conversation = await self.get_conversation(conversation_id)
            if not conversation:
                raise ValueError(f"对话不存在: {conversation_id}")
            
            # 检查对话长度限制
            current_length = conversation.get('message_count', 0)
            if current_length >= self.max_conversation_length:
                # 自动总结并归档旧消息
                await self._auto_summarize_conversation(conversation_id)
            
            # 存储消息到MongoDB
            await self.db_manager.mongodb_client.store_conversation_message(
                conversation_id, message_data
            )
            
            # 更新对话信息
            update_data = {
                'updated_at': timestamp,
                'message_count': current_length + 1
            }
            
            await self.db_manager.mongodb_client.update_conversation(
                conversation_id, update_data
            )
            
            # 更新活跃对话缓存
            if conversation_id in self.active_conversations:
                self.active_conversations[conversation_id].update({
                    'updated_at': timestamp.isoformat(),
                    'message_count': current_length + 1
                })
                
                # 更新Redis
                await self.db_manager.redis_client.set_hash(
                    f"conversation:active:{conversation_id}",
                    self.active_conversations[conversation_id],
                    expire=self.conversation_timeout * 3600
                )
            
            # 存储最近消息到Redis（用于快速上下文检索）
            await self.db_manager.redis_client.list_push(
                f"conversation:messages:{conversation_id}",
                {
                    'message_id': message_id,
                    'role': role,
                    'content': content,
                    'timestamp': timestamp.isoformat()
                },
                max_length=self.context_window_size
            )
            
            # 存储到向量数据库（用于语义搜索）
            if role in ['user', 'assistant']:  # 只存储用户和助手的消息
                await self.db_manager.chromadb_client.store_conversation(
                    message_id, content, {
                        'conversation_id': conversation_id,
                        'user_id': conversation['user_id'],
                        'role': role,
                        'timestamp': timestamp.isoformat()
                    }
                )
            
            logger.debug(f"添加消息: {message_id} - {conversation_id}")
            return message_id
            
        except Exception as e:
            logger.error(f"添加消息失败: {e}")
            raise
    
    async def get_conversation(self, conversation_id: str) -> Optional[Dict[str, Any]]:
        """获取对话信息"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            # 先从缓存获取
            if conversation_id in self.active_conversations:
                cached_data = self.active_conversations[conversation_id]
                
                # 从MongoDB获取完整信息
                full_data = await self.db_manager.mongodb_client.get_conversation(conversation_id)
                if full_data:
                    # 合并缓存和完整数据
                    full_data.update(cached_data)
                    return full_data
            
            # 从MongoDB获取
            return await self.db_manager.mongodb_client.get_conversation(conversation_id)
            
        except Exception as e:
            logger.error(f"获取对话失败: {e}")
            return None
    
    async def get_conversation_context(self, conversation_id: str, 
                                     window_size: Optional[int] = None) -> List[Dict[str, Any]]:
        """获取对话上下文（最近的消息）"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            window_size = window_size or self.context_window_size
            
            # 先从Redis获取最近消息
            recent_messages = await self.db_manager.redis_client.list_range(
                f"conversation:messages:{conversation_id}",
                0, window_size - 1
            )
            
            if recent_messages:
                return recent_messages
            
            # 如果Redis中没有，从MongoDB获取
            return await self.db_manager.mongodb_client.get_conversation_messages(
                conversation_id, limit=window_size
            )
            
        except Exception as e:
            logger.error(f"获取对话上下文失败: {e}")
            return []
    
    async def get_conversation_history(self, conversation_id: str, 
                                     limit: Optional[int] = None,
                                     offset: int = 0) -> List[Dict[str, Any]]:
        """获取对话历史（所有消息）"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            return await self.db_manager.mongodb_client.get_conversation_messages(
                conversation_id, limit=limit, offset=offset
            )
            
        except Exception as e:
            logger.error(f"获取对话历史失败: {e}")
            return []
    
    async def search_conversations(self, query: str, user_id: Optional[str] = None,
                                 limit: int = 10) -> List[Dict[str, Any]]:
        """搜索对话"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            # 1. 向量搜索对话内容
            vector_results = await self.db_manager.chromadb_client.search_conversations(
                query, user_id, limit=limit * 2
            )
            
            # 2. 按对话ID分组
            conversation_scores = {}
            for result in vector_results:
                conv_id = result.get('conversation_id')
                if conv_id:
                    if conv_id not in conversation_scores:
                        conversation_scores[conv_id] = {
                            'conversation_id': conv_id,
                            'max_similarity': 0,
                            'relevant_messages': []
                        }
                    
                    similarity = result.get('similarity', 0)
                    if similarity > conversation_scores[conv_id]['max_similarity']:
                        conversation_scores[conv_id]['max_similarity'] = similarity
                    
                    conversation_scores[conv_id]['relevant_messages'].append(result)
            
            # 3. 获取对话信息并排序
            final_results = []
            for conv_id, score_data in conversation_scores.items():
                try:
                    conv_info = await self.get_conversation(conv_id)
                    if conv_info:
                        final_results.append({
                            'conversation_id': conv_id,
                            'title': conv_info.get('title', ''),
                            'user_id': conv_info.get('user_id'),
                            'created_at': conv_info.get('created_at'),
                            'updated_at': conv_info.get('updated_at'),
                            'message_count': conv_info.get('message_count', 0),
                            'similarity': score_data['max_similarity'],
                            'relevant_messages': score_data['relevant_messages'][:3]  # 最多3条相关消息
                        })
                except Exception as e:
                    logger.error(f"处理搜索结果失败: {conv_id} - {e}")
                    continue
            
            # 按相似度排序
            final_results.sort(key=lambda x: x['similarity'], reverse=True)
            
            logger.debug(f"搜索对话: {query} - 找到 {len(final_results)} 个结果")
            return final_results[:limit]
            
        except Exception as e:
            logger.error(f"搜索对话失败: {e}")
            return []
    
    async def get_user_conversations(self, user_id: str, limit: int = 20,
                                   status: Optional[str] = None) -> List[Dict[str, Any]]:
        """获取用户的对话列表"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            return await self.db_manager.mongodb_client.get_user_conversations(
                user_id, limit=limit, status=status
            )
            
        except Exception as e:
            logger.error(f"获取用户对话失败: {e}")
            return []
    
    async def update_conversation(self, conversation_id: str, updates: Dict[str, Any],
                                user_id: Optional[str] = None) -> bool:
        """更新对话信息"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            # 检查权限
            if user_id:
                conversation = await self.get_conversation(conversation_id)
                if not conversation or conversation.get('user_id') != user_id:
                    logger.warning(f"用户无权更新对话: {user_id} -> {conversation_id}")
                    return False
            
            # 更新数据库
            updates['updated_at'] = datetime.utcnow()
            success = await self.db_manager.mongodb_client.update_conversation(
                conversation_id, updates
            )
            
            # 更新缓存
            if success and conversation_id in self.active_conversations:
                self.active_conversations[conversation_id].update({
                    k: v.isoformat() if isinstance(v, datetime) else v
                    for k, v in updates.items()
                    if k in ['title', 'status', 'updated_at']
                })
                
                # 更新Redis
                await self.db_manager.redis_client.set_hash(
                    f"conversation:active:{conversation_id}",
                    self.active_conversations[conversation_id],
                    expire=self.conversation_timeout * 3600
                )
            
            return success
            
        except Exception as e:
            logger.error(f"更新对话失败: {e}")
            return False
    
    async def close_conversation(self, conversation_id: str, 
                               user_id: Optional[str] = None) -> bool:
        """关闭对话"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            # 更新状态为已关闭
            success = await self.update_conversation(
                conversation_id, {'status': 'closed'}, user_id
            )
            
            if success:
                # 从活跃对话中移除
                if conversation_id in self.active_conversations:
                    del self.active_conversations[conversation_id]
                
                # 从Redis中移除
                await self.db_manager.redis_client.delete(
                    f"conversation:active:{conversation_id}"
                )
                await self.db_manager.redis_client.delete(
                    f"conversation:messages:{conversation_id}"
                )
                
                logger.info(f"关闭对话: {conversation_id}")
            
            return success
            
        except Exception as e:
            logger.error(f"关闭对话失败: {e}")
            return False
    
    async def delete_conversation(self, conversation_id: str,
                                user_id: Optional[str] = None) -> bool:
        """删除对话"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            # 检查权限
            if user_id:
                conversation = await self.get_conversation(conversation_id)
                if not conversation or conversation.get('user_id') != user_id:
                    logger.warning(f"用户无权删除对话: {user_id} -> {conversation_id}")
                    return False
            
            # 从各个存储层删除
            tasks = [
                self.db_manager.mongodb_client.delete_conversation(conversation_id),
                self.db_manager.chromadb_client.delete_conversation(conversation_id),
                self.db_manager.redis_client.delete(f"conversation:active:{conversation_id}"),
                self.db_manager.redis_client.delete(f"conversation:messages:{conversation_id}")
            ]
            
            results = await asyncio.gather(*tasks, return_exceptions=True)
            
            # 检查删除结果
            success = all(not isinstance(result, Exception) for result in results)
            
            if success:
                # 从缓存中移除
                if conversation_id in self.active_conversations:
                    del self.active_conversations[conversation_id]
                
                logger.info(f"删除对话: {conversation_id}")
            else:
                logger.warning(f"删除对话部分失败: {conversation_id}")
            
            return success
            
        except Exception as e:
            logger.error(f"删除对话失败: {e}")
            return False
    
    async def _auto_summarize_conversation(self, conversation_id: str):
        """自动总结对话"""
        try:
            # 获取对话历史
            messages = await self.get_conversation_history(conversation_id)
            
            if len(messages) < self.auto_summary_threshold:
                return
            
            # 简化的总结逻辑（实际应用中可以使用LLM）
            summary_content = f"对话总结 - 共 {len(messages)} 条消息"
            
            # 添加总结消息
            await self.add_message(
                conversation_id, 'system', summary_content,
                {'type': 'summary', 'message_count': len(messages)}
            )
            
            # 清理旧消息的Redis缓存
            await self.db_manager.redis_client.delete(
                f"conversation:messages:{conversation_id}"
            )
            
            logger.info(f"自动总结对话: {conversation_id}")
            
        except Exception as e:
            logger.error(f"自动总结对话失败: {e}")
    
    async def generate_conversation_summary(self, conversation_id: str) -> Optional[str]:
        """生成对话总结"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            # 获取对话历史
            messages = await self.get_conversation_history(conversation_id)
            
            if not messages:
                return None
            
            # 简化的总结生成（实际应用中应使用LLM）
            user_messages = [msg for msg in messages if msg.get('role') == 'user']
            assistant_messages = [msg for msg in messages if msg.get('role') == 'assistant']
            
            summary = f"对话包含 {len(user_messages)} 条用户消息和 {len(assistant_messages)} 条助手回复。"
            
            if user_messages:
                first_message = user_messages[0].get('content', '')[:100]
                summary += f" 对话开始于: {first_message}..."
            
            return summary
            
        except Exception as e:
            logger.error(f"生成对话总结失败: {e}")
            return None
    
    async def cleanup_old_conversations(self, days_threshold: int = 30) -> int:
        """清理旧对话"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            cutoff_date = datetime.utcnow() - timedelta(days=days_threshold)
            
            # 获取要删除的对话
            old_conversations = await self.db_manager.mongodb_client.get_conversations_before_date(
                cutoff_date
            )
            
            deleted_count = 0
            for conv in old_conversations:
                conversation_id = conv.get('conversation_id')
                if conversation_id:
                    success = await self.delete_conversation(conversation_id)
                    if success:
                        deleted_count += 1
            
            logger.info(f"清理旧对话完成: 删除了 {deleted_count} 个对话")
            return deleted_count
            
        except Exception as e:
            logger.error(f"清理旧对话失败: {e}")
            return 0
    
    async def get_user_context(self, user_id: str) -> Dict[str, Any]:
        """获取用户对话上下文"""
        if not self.is_initialized:
            raise RuntimeError("对话管理器未初始化")
        
        try:
            # 获取用户对话
            user_conversations = await self.get_user_conversations(user_id, limit=10)
            
            # 获取活跃对话
            active_conversations = [conv for conv in user_conversations 
                                  if conv.get('status') == 'active']
            
            # 获取最近对话
            recent_conversations = [conv for conv in user_conversations if 
                                  (datetime.utcnow() - conv.get('updated_at', datetime.min)).days <= 7]
            
            return {
                'user_id': user_id,
                'total_conversations': len(user_conversations),
                'active_conversations_count': len(active_conversations),
                'recent_conversations_count': len(recent_conversations),
                'active_conversations': active_conversations[:3],  # 最多3个活跃对话
                'recent_conversations': recent_conversations[:5],  # 最多5个最近对话
                'context_created_at': datetime.utcnow().isoformat()
            }
            
        except Exception as e:
            logger.error(f"获取用户对话上下文失败: {e}")
            return {'user_id': user_id, 'error': str(e)}
    
    async def get_stats(self) -> Dict[str, Any]:
        """获取对话管理器统计信息"""
        try:
            if not self.is_initialized:
                return {'status': 'not_initialized'}
            
            # 获取对话统计
            conversation_stats = await self.db_manager.mongodb_client.get_conversation_stats()
            
            # 获取活跃对话统计
            active_count = len(self.active_conversations)
            
            return {
                'status': 'initialized',
                'config': {
                    'max_conversation_length': self.max_conversation_length,
                    'context_window_size': self.context_window_size,
                    'auto_summary_threshold': self.auto_summary_threshold,
                    'conversation_timeout': self.conversation_timeout,
                    'max_conversations_per_user': self.max_conversations_per_user
                },
                'conversation_stats': conversation_stats,
                'active_conversations': active_count
            }
            
        except Exception as e:
            logger.error(f"获取对话管理器统计失败: {e}")
            return {'error': str(e)}
    
    async def health_check(self) -> Dict[str, Any]:
        """健康检查"""
        try:
            # 检查初始化状态
            initialized = self.is_initialized
            
            # 检查数据库连接
            db_health = await self.db_manager.health_check()
            db_healthy = all(db_health.values())
            
            # 检查活跃对话缓存
            cache_healthy = isinstance(self.active_conversations, dict)
            
            overall_healthy = initialized and db_healthy and cache_healthy
            
            return {
                'healthy': overall_healthy,
                'status': 'healthy' if overall_healthy else 'unhealthy',
                'checks': {
                    'initialized': initialized,
                    'database': db_healthy,
                    'cache': cache_healthy
                },
                'database_health': db_health,
                'active_conversations_count': len(self.active_conversations)
            }
            
        except Exception as e:
            logger.error(f"对话管理器健康检查失败: {e}")
            return {
                'healthy': False,
                'status': 'error',
                'error': str(e)
            }